#!/usr/bin/perl

use lib::abs qw( .. );
use JIP::ToolSet; # load my commonly-used modules in a single import

use Test::More tests => 29;
use Test::MockModule;
use Log;
use Readonly qw( Readonly );
use English qw( -no_match_vars );
use Carp qw( croak );

Readonly my $PATH_TO_LOG_FILE => './test.log';

use_ok('Log');
require_ok('Log');

can_ok(
    'Log',
    qw(
        new
        Note
        Debug
        Warn
        Error
        Fatal
        Dump
        _outputFile
        _logLevel
        _outputHandle
        _outputBuffering
        _getTimeStamp
        _writeMSG
        _getLogMessage
        _isAvailableMessage
    )
);

{
    my $log = Log->new(
        log_file  => $PATH_TO_LOG_FILE,
        log_level => 'error',
        buffering => 1,
    );

    isa_ok( $log, 'Log' );
    isa_ok( $log, 'Class::Base' );
    isa_ok( $log, 'Class::Accessor::Fast' );

    is( $log->_outputFile,      $PATH_TO_LOG_FILE, 'outputFile accessor' );
    is( $log->_outputBuffering, 1,                 'outputBuffering accessor' );
    is( $log->_logLevel,        'error',           'logLevel accessor' );

    try {
        $log->_outputFile = 'tratata';
    }
    catch {
        like(
            $ARG,
            qr/^Can't modify non-lvalue subroutine call at/,
            'r.o. access to _outputFile'
        );
    };

    try {
        $log->_logLevel = 'tratata';
    }
    catch {
        like(
            $ARG,
            qr/^Can't modify non-lvalue subroutine call at/,
            'r.o. access to _logLevel'
        );
    };

    try {
        $log->_outputHandle = 'tratata';
    }
    catch {
        like(
            $ARG,
            qr/^Can't modify non-lvalue subroutine call at/,
            'r.o. access to _outputHandle'
        );
    };

    try {
        $log->_outputBuffering = 'tratata';
    }
    catch {
        like(
            $ARG,
            qr/^Can't modify non-lvalue subroutine call at/,
            'r.o. access to _outputBuffering'
        );
    };

    is( $log->_isAvailableMessage('fatal'), 'fatal', 'fatal - _isAvailableMessage method' );
    is( $log->_isAvailableMessage('error'), 'error', 'error - _isAvailableMessage method' );
    is( $log->_isAvailableMessage('dump'),  'dump',  'dump  - _isAvailableMessage method' );
    is( $log->_isAvailableMessage('note'),  undef,   'note  - _isAvailableMessage method' );

    like(
        $log->_getLogMessage( message_type => 'N', message_text => 'tratata' ),
        qr/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\s\w\s{5}:\stratata$/x,
        "'N' log message"
    );

    like(
        $log->_getLogMessage( message_type => 'DEBUG', message_text => 'tratata' ),
        qr/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\sDEBUG\s:\stratata$/x,
        "'DEBUG' log message"
    );

    like(
        $log->_getLogMessage( message_type => 'DEBUGGG', message_text => 'tratata' ),
        qr/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\sDEBUGGG\s:\stratata$/x,
        "'DEBUGGG' log message"
    );

    like(
        $log->_getTimeStamp,
        qr/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$/x,
        'time_stamp'
    );

    unlink $PATH_TO_LOG_FILE;
}

{
    my $log;

    try {
        $log = Log->new( buffering => 1 );
    }
    catch {
        like(
            $ARG,
            qr/^required parameter "log_file" not defined at /,
            'constructor error'
        );
    };

    is( $log, undef, "emty class" );
}

{
    my $log;

    try {
        $log = Log->new(
            log_file  => $PATH_TO_LOG_FILE,
            buffering => 1,
        );
    }
    catch {
        like(
            $ARG,
            qr/^required parameter "log_level" not defined at /,
            "constructor error"
        );
    };
}

{
    my $log = Log->new( log_file => $PATH_TO_LOG_FILE, log_level => 'all' );

    my $module = Test::MockModule->new( 'Log' );

    $module->mock(
        '_writeMSG',
        sub {
            my $self = shift; my %args = @ARG;

            is(
                $args{'message_type'},
                'DEBUG',
                'mock testing - "message_type" in "_writeMSG"'
            );

            is(
                $args{'message_text'},
                'you screwed up, but thats ok',
                'mock testing - "message_text" in "_writeMSG"'
            );
        }
    );

    $log->_writeMSG(
        message_type => 'DEBUG',
        message_text => 'you screwed up, but thats ok',
    );

    $module->mock(
        '_getLogMessage',
        sub {
            my $self = shift; my %args = @ARG;

            is(
                $args{'message_type'},
                'FATAL',
                'mock testing - "message_type" in "_getLogMessage"'
            );

            is(
                $args{'message_text'},
                'its over...',
                'mock testing - "message_text" in "_getLogMessage"'
            );
        }
    );

    $log->_getLogMessage(
        message_type => 'FATAL',
        message_text => 'its over...',
    );

    unlink $PATH_TO_LOG_FILE;
}

{
    open( LOG, '>', $PATH_TO_LOG_FILE ) or croak $OS_ERROR; # touch empty file
    close( LOG ) or croak $OS_ERROR;                        #

    try {
        Log->new( log_file => $PATH_TO_LOG_FILE, log_level => 'all' );
    }
    catch {
        like( $ARG, qr/^couldn't open log file :/, 'crash on existing file' );
    };

    unlink $PATH_TO_LOG_FILE;
}
